﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Text.RegularExpressions;

namespace Janus.BaseEntitys
{
    /// <summary>
    /// 查询帮助类
    /// </summary>
    [Serializable]
    public class Querier
    {
        private List<QueryBody> QueryBodys { get; set; }

        /// <summary>
        /// 排序条件
        /// </summary>
        public string Orders { get; set; }

        public Querier()
        {
            QueryBodys = QueryBodys ?? new List<QueryBody>();
        }

        public Querier(string body, List<object> parameters = null, string andOr = null) : this()
        {
            QueryBody queryBody = new QueryBody(body, parameters, andOr);
            this.QueryBodys.Add(queryBody);
        }

        public List<QueryBody> Add(string body, List<object> parameters = null, string andOr = " and ")
        {
            if (this.QueryBodys.Count == 0) andOr = "";
            QueryBody queryBody = new QueryBody(body, parameters, andOr);
            this.QueryBodys.Add(queryBody);
            return QueryBodys;
        }

        public Querier Where(string body, params object[] parameters)
        {
            this.Add(body, parameters.ToList());
            return this;
        }

        public Querier And(string body, params object[] parameters)
        {
            this.Add(body, parameters.ToList());
            return this;
        }

        public Querier Or(string body, params object[] parameters)
        {
            this.Add(body, parameters.ToList(), " or ");
            return this;
        }


        public virtual Querier OrderBy<TEntity>(Expression<Func<TEntity, object>> order) where TEntity : Entity
        {
            var member = GetMemberExpression(order);
            var name = member.Member.Name;
            this.Orders += string.Format("{0} ASC", string.IsNullOrEmpty(this.Orders) ? "ORDER BY [" + name + "]" : ",[" + name + "]");
            return this;
        }

        public virtual Querier OrderDescBy<TEntity>(Expression<Func<TEntity, object>> order) where TEntity : Entity
        {
            var member = GetMemberExpression(order);
            var name = member.Member.Name;
            this.Orders += string.Format("{0} DESC", string.IsNullOrEmpty(this.Orders) ? "ORDER BY [" + name + "]" : ",[" + name + "]");
            return this;
        }

        public virtual Querier Select<TSource, TResult>(Func<TSource, TResult> selector)
        {
            throw new NotImplementedException();//未实现
            return this;
        }

        public virtual Querier SelectMany<TSource, TResult>(Func<TSource, TResult> selector)
        {
            throw new NotImplementedException();//未实现
            return this;
        }

        protected virtual MemberExpression GetMemberExpression(Expression expression)
        {
            if (expression == null)
                return null;
            switch (expression.NodeType)
            {
                case ExpressionType.Lambda:
                    return GetMemberExpression(((LambdaExpression)expression).Body);
                case ExpressionType.Convert:
                    return GetMemberExpression(((UnaryExpression)expression).Operand);
                case ExpressionType.Equal:
                case ExpressionType.NotEqual:
                case ExpressionType.GreaterThan:
                case ExpressionType.LessThan:
                case ExpressionType.GreaterThanOrEqual:
                case ExpressionType.LessThanOrEqual:
                    return GetMemberExpression(((BinaryExpression)expression).Left);
                case ExpressionType.Call:
                    return GetMemberExpression(((MethodCallExpression)expression).Object);
                case ExpressionType.MemberAccess:
                    return (MemberExpression)expression;
            }
            return null;
        }

        public string CombineWhere(out List<object> outParameters)
        {
            string where = string.Empty;
            var parameters = new List<object>();
            if (this.QueryBodys != null && this.QueryBodys.Count > 0)
            {
                this.QueryBodys.ForEach(c =>
                {
                    where += string.Format(" {0} ({1}) ", c.AndOr, c.Body);
                    parameters.AddRange(c.Parameters);
                });
                Regex reg = new Regex(@"\{(@|\w|\d)*\}");
                int i = 0;
                where = reg.Replace(where, c =>
                 {
                     string result = string.Format("@{0}", i);
                     i++;
                     return result;
                 });
            }
            outParameters = parameters;
            return where;
        }

        public Expression<Func<T, S>> ToExpression<T, S>() where T : Entity
        {
            List<object> outParameters = null;
            string where = this.CombineWhere(out outParameters);
            if (!string.IsNullOrEmpty(where))
            {
                var expression = System.Linq.Dynamic.DynamicExpression.ParseLambda<T, S>(where, outParameters.ToArray());
                return expression;
            }
            else
            {
                return null;
            }
        }

    }

    /// <summary>
    /// 查询条件体
    /// </summary>
    [Serializable]
    public class QueryBody
    {
        public QueryBody(string body, List<object> parameters = null, string andOr = null)
        {
            Parameters = Parameters ?? new List<object>();
            this.Body = body;
            this.AndOr = andOr;
            if (parameters != null)
            {
                this.Parameters.AddRange(parameters);
            }
        }
        /// <summary>
        /// 表达式
        /// </summary>
        public string Body { get; set; }
        /// <summary>
        /// 参数
        /// </summary>
        public List<object> Parameters { get; set; }
        /// <summary>
        /// And Or
        /// </summary>
        public string AndOr { get; set; }
    }
       
}
